/***************************************************************************
*===========================================================================
****************************************************************************
* Title        : GDD_Interface.c
*
* Description  : Gesture Detection Driver (GDD) interface file 
*
* Author  : Misael Munoz
*
****************************************************************************
*===========================================================================
****************************************************************************/


#define GDD_Interface_C

/* System-headerfiles */


/* Foreign headerfiles */
#include "MPR121.h"
#include "port.h"
#include "evhdl_iterface.h"
#include "Sw_Timers.h"
#include "TPM_interface.h"

/* Own headerfiles */
#include "GDD_Interface.h"



/***************************************************************************
* GLOBAL DEFINITIONS
****************************************************************************/
extern uint16 GDD__u16NewElectrodeStatus;

GDD__tstNiData GDD__stData;

uint16 GDD__u16RedPWMValue = 0;
uint16 GDD__u16GreenPWMValue = 0;
uint16 GDD__u16BluePWMValue = 0;

/***************************************************************************
* FILE LOCAL DEFINITIONS
****************************************************************************/

/******************************************************************************
* FILE LOCAL FUNCTION PROTOTYPES
******************************************************************************/



/******************************************************************************
* FUNCTION DEFINITIONS
******************************************************************************/

/* File Local Scope */

static void GDD__vClearTrackerBuffer(void)
{
   uint8 x;
   for (x = 0; x < GDD__nTrackerbuffSize; x++)
   {
      GDD__stData.u8bTrackerbuff[x] = 0;
   }
}

static void GDD__vSettoClearState(void)
{
   uint8 x;
   for (x = 0; x < GDD__nElectrodes; x++)
   {
      GDD__stData.stbElectrodes[x].CurrState = enCleared;
   }
}

static void GDD__vTapStateMachine(uint16 u16NewStates)
{
   uint16 u16WorkingStates = 0;
   uint8 u8CurrElectrode = 0;
   uint8 u8Transition = 0;

   /*Filter witch electrodes had changed */
   u16WorkingStates = GDD__stData.u16PastElectrodeStatus ^ u16NewStates;

   u8CurrElectrode = GDD__u8ElectrodeFIFO(&u16WorkingStates);

   if (u8CurrElectrode != 0xFF)
   {
      if (((u16WorkingStates >> u8CurrElectrode) <= 0x01) &&
         ((u16NewStates >> u8CurrElectrode) <= 0x01))
      {
         /*get transition */
         u8Transition = (uint8) (0x01 & (u16NewStates >> u8CurrElectrode));

         switch (GDD__stData.stbElectrodes[u8CurrElectrode].CurrState)
         {
         case enCleared:
            if (u8Transition == GDD__nT_CeroToOne)
            {
               GDD__stData.stbElectrodes[u8CurrElectrode].CurrState = enActive;
            }
            else
            {
               /*Invalid transition*/
               //GDD__DEBUG_BKPT;
            }
            break;

         case enActive:
            if (u8Transition == GDD__nT_OneToCero)
            {
               GDD__stData.stbElectrodes[u8CurrElectrode].CurrState = enTap;
               /*Start Timer*/
               SwTimer_StartTimer(GDD__stData.u8SwTimer, GDD__nTapTimer);
            }
            else
            {
               /*Invalid transition*/
               //GDD__DEBUG_BKPT;
            }
            break;

         case enTap:
            if (u8Transition == GDD__nT_CeroToOne)
            {
               GDD__stData.stbElectrodes[u8CurrElectrode].CurrState = enActive2;
               /*Start Timer*/
               SwTimer_StartTimer(GDD__stData.u8SwTimer, GDD__nTapTimer);

            }
            else
            {
               /*Invalid transition*/
               //GDD__DEBUG_BKPT;
            }

            break;

         case enActive2:
            if (u8Transition == GDD__nT_OneToCero)
            {
               GDD__stData.stbElectrodes[u8CurrElectrode].CurrState = enTap2;
               /*Start Timer*/
               SwTimer_StartTimer(GDD__stData.u8SwTimer, GDD__nTapTimer);
            }
            else
            {
               /*Invalid transition*/
               //GDD__DEBUG_BKPT;
            }
            break;

         case enTap2:
            if (u8Transition == GDD__nT_CeroToOne)
            {
               GDD__stData.stbElectrodes[u8CurrElectrode].CurrState = enActive3;
               /*Start Timer*/
               SwTimer_StartTimer(GDD__stData.u8SwTimer, GDD__nTapTimer);
            }
            else
            {
               /*Invalid transition*/
               //GDD__DEBUG_BKPT;
            }
            break;

         case enActive3:
            if (u8Transition == GDD__nT_OneToCero)
            {
               GDD__stData.stbElectrodes[u8CurrElectrode].CurrState = enTap3;
            }
            else
            {
               /*Invalid transition*/
               //GDD__DEBUG_BKPT;
            }
            break;

         case enTap3: /*Same as default*/
         default:
            /*Do noting*/
            break;
         }
      }
   }
}


static void GDD__vTrackPattern(uint16 u16NewStates)
{

   uint16 u8FilterElectrodes = 0;
   uint8 x = 0;
   uint8 u8Result = 0;

   for (x = 0; x < GDD__nRGBnumber; x++)
   {
      if (x == GDD__nRGBBlueID)
      {
         u8FilterElectrodes = (GDD__stData.u16PastElectrodeStatus & 0x000F);
         u8Result = GDD__u8GetColorPattern(u8FilterElectrodes, u16NewStates);
         if (GDD__nIncrement == u8Result)
         {
            if ((GDD__u16BluePWMValue + GDD__nFixedValue) <= DUTY_MAX)
            {
               GDD__u16BluePWMValue += GDD__nFixedValue;
               GDD__SetPWMBlue(GDD__u16BluePWMValue);
            }
         }
         else if (GDD__nDecrement == u8Result)
         {
            if ((GDD__u16BluePWMValue - GDD__nFixedValue) >= DUTY_MIN)
            {
               GDD__u16BluePWMValue -= GDD__nFixedValue;
               GDD__SetPWMBlue(GDD__u16BluePWMValue);
            }
         }
      }
      else if (x == GDD__nRGBGreenID)
      {
         u8FilterElectrodes = (GDD__stData.u16PastElectrodeStatus & 0x00F0);
         u8Result = GDD__u8GetColorPattern(u8FilterElectrodes, u16NewStates);
         if (GDD__nIncrement == u8Result)
         {
            if ((GDD__u16GreenPWMValue + GDD__nFixedValue) <= DUTY_MAX)
            {
               GDD__u16GreenPWMValue += GDD__nFixedValue;
               GDD__SetPWMGreen(GDD__u16GreenPWMValue);
            }
         }
         else if (GDD__nDecrement == u8Result)
         {
            if ((GDD__u16GreenPWMValue - GDD__nFixedValue) >= DUTY_MIN)
            {
               GDD__u16GreenPWMValue -= GDD__nFixedValue;
               GDD__SetPWMGreen(GDD__u16GreenPWMValue);
            }
         }
      }
      else
      {
         u8FilterElectrodes = (GDD__stData.u16PastElectrodeStatus & 0x0F00);
         u8Result = GDD__u8GetColorPattern(u8FilterElectrodes, u16NewStates);
         if (GDD__nIncrement == u8Result)
         {
            if ((GDD__u16RedPWMValue + GDD__nFixedValue) <= DUTY_MAX)
            {
               GDD__u16RedPWMValue += GDD__nFixedValue;
               GDD__SetPWMRed(GDD__u16RedPWMValue);
            }
         }
         else if (GDD__nDecrement == u8Result)
         {
            if ((GDD__u16RedPWMValue - GDD__nFixedValue) >= DUTY_MIN)
            {
               GDD__u16RedPWMValue -= GDD__nFixedValue;
               GDD__SetPWMRed(GDD__u16RedPWMValue);
            }

         }
      }

   }
}

static uint8 GDD__u8GetColorPattern(uint16 u16RGBFiltered, uint16 u16NewStates)
{
   uint8 u8WorkElectrode = 0;
   uint16 u16ShiftedElectrodes = 0;
   uint8 u8Pointer = 0;
   uint8 u8PointerMinus1 = 0;
   uint8 u8PointerPlus1 = 0;
   uint8 u8Return = 0xFF;

   u8WorkElectrode = GDD__u8ElectrodeFIFO(&u16RGBFiltered);
   u16ShiftedElectrodes = u16RGBFiltered >> u8WorkElectrode;

   if (u16ShiftedElectrodes == 0x01)
   {
      u8Pointer = (uint8) ((u16NewStates >> u8WorkElectrode) & 0x01);
      u8PointerMinus1 = (uint8) ((u16NewStates >> (u8WorkElectrode - 1)) & 0x01);
      u8PointerPlus1 = (uint8) ((u16NewStates >> (u8WorkElectrode + 1)) & 0x01);
      if (u8Pointer == 0x00)
      {
         if (u8PointerPlus1 == 0x01)
         {
            u8Return = GDD__nIncrement;
         }
         else if (u8PointerMinus1 == 0x01)
         {
            u8Return = GDD__nDecrement;
         }
      }
      else if (u8Pointer == 0x01)
      {
         if (u8PointerPlus1 == 0x01)
         {
            u8Return = GDD__nIncrement;
         }
         else if (u8PointerMinus1 == 0x01)
         {
            u8Return = GDD__nDecrement;
         }
      }

   }
   else if (u16ShiftedElectrodes == 0x03)
   {
      u8Pointer = (uint8) ((u16NewStates >> u8WorkElectrode) & 0x01);
      u8PointerPlus1 = (uint8) ((u16NewStates >> (u8WorkElectrode + 1)) & 0x01);
      if (u8Pointer == 0x01)
      {
         u8Return = GDD__nDecrement;

      }
      else if (u8PointerPlus1 == 0x01)
      {
         u8Return = GDD__nIncrement;
      }
   }

   return u8Return;
}

static uint8 GDD__u8ElectrodeFIFO(uint16 *u16States)
{
   uint8 u8FirstBit = 0;
   uint8 u8CurrBit = 0;
   uint16 u16temp = 0;
   do
   {
      u16temp = *u16States >> u8FirstBit;
      u8CurrBit = (uint16) (0x01 & u16temp);
      u8FirstBit++;
   } while ((u8CurrBit == 0) && (u8FirstBit < GDD__nElectrodes));

   if (u8FirstBit <= GDD__nElectrodes)
   {
      return (u8FirstBit - 1u);
   }
   else
   {
      return 0xFF;
   }
}


/* System Wide Scope */  


void GDD_vInit(void)
{
   
   /*Clear Gesture Detection Driver local data */
   GDD__stData.u8Trackerpointer = 0;   
   GDD__stData.u16PastElectrodeStatus = 0;
   GDD__vClearTrackerBuffer();   
   GDD__vSettoClearState();
   GDD__u16RedPWMValue = DUTY_MAX;
   GDD__u16GreenPWMValue = DUTY_MAX;
   GDD__u16BluePWMValue = DUTY_MAX;
   
   /*Create the SW Timer for tap time detection */
   GDD__stData.u8SwTimer = SwTimer_CreateTimer(&GDD_vTimerCallback);
   
   /*Register the GDD New Data Event in the system*/
   EVHD_vRegister(EV_GDD_NewData_Event);
   EVHD_vRegister(EV_GDD_TapTap_Event);
}

void GDD_vTimerCallback(void)
{
   uint8 x;
   for (x = 0; x < GDD__nElectrodes; x++)
   {
      if((enTap2 == GDD__stData.stbElectrodes[x].CurrState) 
            || (enTap3 == GDD__stData.stbElectrodes[x].CurrState))
      {
         /*If Tap detection was successful */
         GDD__stData.u8TapTappointer = x;
         EVHD_vSendEvent(EV_GDD_TapTap_Event);         
         
      }else if(enTap == GDD__stData.stbElectrodes[x].CurrState)
      {
         GDD__stData.stbElectrodes[x].CurrState = enCleared;
      }
      else if((enActive2 == GDD__stData.stbElectrodes[x].CurrState)
            || (enActive3 == GDD__stData.stbElectrodes[x].CurrState))
      {
         GDD__stData.stbElectrodes[x].CurrState = enActive;
      }
      else
      {
         /*Do Nothing*/
      }
   }
      
}

void GDD_vTapTapEventHandler(void)
{   

   if (8u == GDD__stData.u8TapTappointer 
         || 9u == GDD__stData.u8TapTappointer 
         || 10u == GDD__stData.u8TapTappointer 
         || 11u == GDD__stData.u8TapTappointer)
   {
      if (enTap3 == GDD__stData.stbElectrodes[GDD__stData.u8TapTappointer].CurrState)
      {
         GDD__u16RedPWMValue = DUTY_MIN;
         GDD__SetPWMRed(GDD__u16RedPWMValue);
      }
      else
      {         
         GDD__u16RedPWMValue = DUTY_MAX;
         GDD__SetPWMRed(GDD__u16RedPWMValue);
      }
   }
   else if (4u == GDD__stData.u8TapTappointer 
         || 5u == GDD__stData.u8TapTappointer 
         || 6u == GDD__stData.u8TapTappointer 
         || 7u == GDD__stData.u8TapTappointer)
   {
      if (enTap3 == GDD__stData.stbElectrodes[GDD__stData.u8TapTappointer].CurrState)
      {
         GDD__u16GreenPWMValue = DUTY_MIN;
         GDD__SetPWMGreen(GDD__u16GreenPWMValue);         
      }
      else
      {         
         GDD__u16GreenPWMValue = DUTY_MAX;
         GDD__SetPWMGreen(GDD__u16GreenPWMValue);  
      }
   }
   else
   {
      if (enTap3 == GDD__stData.stbElectrodes[GDD__stData.u8TapTappointer].CurrState)
      {         
         GDD__u16BluePWMValue = DUTY_MIN;
         GDD__SetPWMBlue(GDD__u16BluePWMValue);  
      }
      else
      {         
         GDD__u16BluePWMValue = DUTY_MAX;
         GDD__SetPWMBlue(GDD__u16BluePWMValue);  
      }

   }
   
   GDD__stData.stbElectrodes[GDD__stData.u8TapTappointer].CurrState = enCleared;

}

void GDD_vNewDataEventHandler(void)
{

   GDD__vTapStateMachine(GDD__u16NewElectrodeStatus);
   GDD__vTrackPattern(GDD__u16NewElectrodeStatus);
   GDD__stData.u16PastElectrodeStatus = GDD__u16NewElectrodeStatus;

}



















